package utils

import (
	"fmt"
	"go_web/internal/res/res_sys"
	"strings"
	"unicode"

	"github.com/mojocn/base64Captcha"
	"gopkg.in/gomail.v2"
)

func ConvertToSnakeCase(s string) string {
	var result []rune
	for i, ch := range s {
		// 如果是大写字母并且不是第一个字母
		if unicode.IsUpper(ch) && i > 0 {
			result = append(result, '_')                 // 加上下划线
			result = append(result, unicode.ToLower(ch)) // 转为小写
		} else {
			result = append(result, ch) // 保持原字符
		}
	}
	return string(result)
}

// SnakeToCamel 蛇形命名转小驼峰命名 (user_name → userName)
func SnakeToCamel(s string) string {
	return snakeToCamelCase(s, false)
}

// SnakeToPascal 蛇形命名转大驼峰命名 (user_name → UserName)
func SnakeToPascal(s string) string {
	return snakeToCamelCase(s, true)
}

// snakeToCamelCase 通用的蛇形转驼峰核心函数
func snakeToCamelCase(s string, pascalCase bool) string {
	if s == "" {
		return ""
	}

	words := strings.Split(s, "_")
	var result strings.Builder

	for i, word := range words {
		if word == "" {
			continue
		}

		// 处理每个单词
		if i == 0 && !pascalCase {
			// 小驼峰：第一个单词全小写
			if len(word) > 0 {
				result.WriteString(strings.ToLower(word[:1]))
				if len(word) > 1 {
					result.WriteString(word[1:])
				}
			}
		} else {
			// 大驼峰或非首单词：首字母大写
			if len(word) > 0 {
				result.WriteString(strings.ToUpper(word[:1]))
				if len(word) > 1 {
					result.WriteString(word[1:])
				}
			}
		}
	}

	return result.String()
}

// 判断是否为乐观锁错误
func IsOptimisticLockError(err error) bool {
	// GORM 的乐观锁插件会返回特定的错误
	// 通常包含 "optimistic lock" 或 "conflict" 等关键词
	if err == nil {
		return false
	}

	// 检查错误信息中是否包含乐观锁相关的关键词
	errMsg := err.Error()
	return ContainsString(errMsg, "optimistic") ||
		ContainsString(errMsg, "lock") ||
		ContainsString(errMsg, "conflict") ||
		ContainsString(errMsg, "version") ||
		ContainsString(errMsg, "stale")
}

func ContainsString(s, substr string) bool {
	if len(substr) > len(s) {
		return false
	}
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}

// 生成图片验证码
func GenerateGraphValidateCode() (*res_sys.ImgCaptcha, error) {
	driver := base64Captcha.DriverDigit{
		Height:   40,
		Width:    120,
		Length:   6,
		MaxSkew:  0.3,
		DotCount: 20,
	}
	captcha := base64Captcha.NewCaptcha(&driver, base64Captcha.DefaultMemStore)
	id, b64s, answer, err := captcha.Generate()
	if err != nil {
		return nil, err
	}
	return &res_sys.ImgCaptcha{
		ValidCode: id,
		Base64:    b64s,
		Code:      answer,
	}, nil
}

// 生成简单算术验证码
func GenerateEasyMathValidateCode() (*res_sys.ImgCaptcha, error) {
	// 创建数学验证码驱动
	driver := base64Captcha.DriverMath{
		Height:          60,
		Width:           180,
		NoiseCount:      2,
		ShowLineOptions: 2,
	}

	// 生成验证码
	captcha := base64Captcha.NewCaptcha(&driver, base64Captcha.DefaultMemStore)
	id, b64s, answer, err := captcha.Generate()
	if err != nil {
		return nil, fmt.Errorf("failed to generate captcha: %w", err)
	}

	// 创建返回结果
	result := &res_sys.ImgCaptcha{
		ValidCode: id,
		Base64:    b64s,
		Code:      answer,
	}

	return result, nil
}

// 生成随机字符串验证码
func GenerateStrCode(length int) string {
	return base64Captcha.RandText(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
}

// 验证图形验证码
func VerifyCode(id, answer string) bool {
	// 使用默认的内存存储验证答案
	return base64Captcha.DefaultMemStore.Verify(id, answer, true)
}

// 发送邮件
func SendEmail(to, subject, body string) error {
	from := "yucodesspace@qq.com"
	password := "rhpohfwzwyjcbjie" // 授权码
	smtpHost := "smtp.qq.com"      // smtp 服务器
	smtpPort := 587

	m := gomail.NewMessage()
	m.SetHeader("From", from)
	m.SetHeader("To", to)
	m.SetHeader("Subject", subject)
	m.SetBody("text/html", body)
	d := gomail.NewDialer(smtpHost, smtpPort, from, password)
	if err := d.DialAndSend(m); err != nil {
		return err
	}
	return nil
}

// 提取url中最后 / 部分
func ExtractLastPath(url string, isSuffix bool) string {
	retStr := url[strings.LastIndex(url, "/")+1:]
	if isSuffix {
		return retStr
	} else {
		isHasSuffix := strings.Contains(retStr, ".")
		if isHasSuffix {
			return retStr[:strings.LastIndex(retStr, ".")]
		} else {
			return retStr
		}
	}
}

// 拿到文件名的后缀字符串
func GetFileExtension(fileName string) string {
	if fileName != "" && strings.LastIndex(fileName, ".") != -1 &&
		strings.LastIndex(fileName, ".") != len(fileName)-1 {
		return fileName[strings.LastIndex(fileName, ".")+1:]
	}
	return ""
}
